package imp

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"

	"github.com/google/uuid"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"go.uber.org/zap"
	"google.golang.org/grpc"

	"bgs/conf"
	"bgs/grpc/gen/proxy/thirdparty"
	"bgs/pkg/cos"
	// "bgs/qiniu"
	"bgs/util"
)

// ThirdPartyService 第三方服务
type ThirdPartyService struct {
	slog *zap.SugaredLogger
	cfg  *conf.WechatSection
	// qiniu *qiniu.Qiniu
	cos *cos.Cos
	thirdparty.UnimplementedBgsVendorServiceServer
}

// NewWechatService initialization
func NewWechatService(cfg *conf.WechatSection, cos *cos.Cos, slog *zap.SugaredLogger) *ThirdPartyService {
	return &ThirdPartyService{
		slog:                                slog,
		cfg:                                 cfg,
		cos:                                 cos,
		UnimplementedBgsVendorServiceServer: thirdparty.UnimplementedBgsVendorServiceServer{},
	}
}

// RegisterService register service
func (t *ThirdPartyService) RegisterService(s *grpc.Server) {
	thirdparty.RegisterBgsVendorServiceServer(s, t)
}

// MinaCode2Session 小程序换取 session key
func (t *ThirdPartyService) MinaCode2Session(ctx context.Context, in *thirdparty.MinaCode2SessionReq) (*thirdparty.MinaCode2SessionResp, error) {
	api := "https://api.weixin.qq.com/sns/jscode2session"
	param := map[string]interface{}{
		"appid":      t.cfg.MinaAppID,
		"secret":     t.cfg.MinaSecret,
		"js_code":    in.GetJSCode(),
		"grant_type": "authorization_code",
	}

	body, err := util.GetRequest().Send(ctx, "GET", api, param, nil, 2)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	type resp struct {
		Openid     string `json:"openid"`
		SessionKey string `json:"session_key"`
		Unionid    string `json:"unionid"`
		Errcode    int    `json:"errcode"`
		Errmsg     string `json:"errmsg"`
	}
	r := &resp{}
	if err = json.Unmarshal(body, r); err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if r.Errcode != 0 {
		return nil, status.Error(codes.Internal, r.Errmsg)
	}

	return &thirdparty.MinaCode2SessionResp{
		OpenId:     r.Openid,
		SessionKey: r.SessionKey,
		UnionId:    r.Unionid,
	}, nil
}

// MinaGetPhoneNumber 手机号解密
func (t *ThirdPartyService) MinaGetPhoneNumber(_ context.Context, in *thirdparty.MinaGetPhoneNumberReq) (*thirdparty.MinaGetPhoneNumberResp, error) {
	data, err := util.NewEncrypt().MinaAESDecrypt(in.GetEncryptedData(), in.GetSessionKey(), in.GetIV())
	if err != nil {
		return nil, status.Error(codes.InvalidArgument, err.Error())
	}
	type PhoneData struct {
		//PhoneNumber     string `json:"phoneNumber"`
		PurePhoneNumber string `json:"purePhoneNumber"`
		CountryCode     string `json:"countryCode"`
	}
	phone := &PhoneData{}
	if err = json.Unmarshal(data, phone); err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	return &thirdparty.MinaGetPhoneNumberResp{
		PhoneNumber: phone.PurePhoneNumber,
		CountryCode: phone.CountryCode,
	}, nil
}

// MinaCreateQrCode 小程序生成二维码
func (t *ThirdPartyService) MinaCreateQrCode(ctx context.Context, in *thirdparty.MinaCreateQrCodeReq) (*thirdparty.MinaCreatQrCodeResp, error) {
	api := "https://api.weixin.qq.com/wxa/getwxacodeunlimit"
	api = fmt.Sprintf("%s?access_token=%s", api, in.GetAccessToken())
	param := map[string]interface{}{
		"scene":      in.Scene,
		"auto_color": in.AutoColor,
		"is_hyaline": in.IsHyaline,
	}
	if in.Page != "" {
		param["page"] = in.Page
	}
	if in.Width != 0 {
		param["width"] = in.Width
	}
	if in.LineColor != nil {
		param["line_color"] = map[string]interface{}{
			"r": in.LineColor.R,
			"g": in.LineColor.G,
			"b": in.LineColor.B,
		}
	}
	body, err := util.GetRequest().Send(ctx, "POST", api, param, nil, 2)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if bytes.HasPrefix(body, []byte("{")) {
		type errInfo struct {
			Errcode int    `json:"errcode"`
			ErrMsg  string `json:"errmsg"`
		}
		ei := &errInfo{}
		if err = json.Unmarshal(body, ei); err != nil {
			return nil, status.Error(codes.Internal, err.Error())
		}
		return nil, status.Error(codes.Internal, ei.ErrMsg)
	}
	uid, _ := uuid.NewUUID()
	fileName := fmt.Sprintf("mina_qrcode_%s.jpg", uid.String())
	// uri, _, err := t.qiniu.UploadByBuffer(ctx, bytes.NewBuffer(body), fileName)
	t.slog.Infof("MinaCreateQrCode upload file name by cos=>%s, length:%d", fileName, len(body))
	uri, err := t.cos.Upload(ctx, bytes.NewReader(body), fileName)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	return &thirdparty.MinaCreatQrCodeResp{Uri: uri}, nil
}

// MinaGetAccessToken 小程序获取accessToken
func (t *ThirdPartyService) MinaGetAccessToken(ctx context.Context, _ *thirdparty.Empty) (*thirdparty.MinaAccessTokenResp, error) {
	api := "https://api.weixin.qq.com/cgi-bin/token"
	param := map[string]interface{}{
		"appid":      t.cfg.MinaAppID,
		"secret":     t.cfg.MinaSecret,
		"grant_type": "client_credential",
	}
	body, err := util.GetRequest().Send(ctx, "GET", api, param, nil, 2)
	if err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	type token struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int32  `json:"expires_in"`
		Errcode     int    `json:"errcode"`
		Errmsg      string `json:"errmsg"`
	}
	resp := &token{}
	if err = json.Unmarshal(body, resp); err != nil {
		return nil, status.Error(codes.Internal, err.Error())
	}
	if resp.Errcode != 0 {
		return nil, status.Error(codes.Internal, resp.Errmsg)
	}
	return &thirdparty.MinaAccessTokenResp{
		AccessToken: resp.AccessToken,
		ExpiresIn:   resp.ExpiresIn,
	}, nil
}

// QiniuGetUploadToken 图片上传token(废弃不用,改为cos后不需要)
func (t *ThirdPartyService) QiniuGetUploadToken(ctx context.Context, in *thirdparty.QiniuGetUploadTokenReq) (*thirdparty.QiniuGetUploadTokenResp, error) {
	return &thirdparty.QiniuGetUploadTokenResp{
		UToken:  "obsolete",
		Expires: 0,
	}, nil
}
